package com.cqhilink.api.common.utils;

import org.apache.commons.lang.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Random;
import java.util.regex.Pattern;

/**
 * Created by sugongche on 2016/6/15.
 */
public class StringUtil {
    /**
     * Str转int
     *
     * @param str
     * @return
     */
    public static int toInt(String str) {
        if (null == str || "".equals(str)) {
            return 0;
        } else {
            return Integer.parseInt(str);
        }
    }

    /**
     * 匹配中国邮政编码
     * 来源：http://blog.csdn.net/paincupid/article/details/50321129（百度：java 正则表达式 邮政编码 ）
     * 注意：邮编开头可以为0
     * 邮政编码格式：我国采用四级六位编码制，邮政编码“130021”“13”代表吉林省，“00”代表省会长春，“21”代表所在投递区。
     *
     * @param postCode 邮政编码
     * @return 验证成功返回true，验证失败返回false
     */
    public static boolean isPostCode(String postCode) {
        if (postCode == null || postCode.equals("")) {
            return false;
        }

        String reg = "\\d{6}";

        //两种写法均可以：
        //return postCode.matches(reg);
        return Pattern.matches(reg, postCode);
    }

    /**
     * 验证中国内地的手机号码
     * 来源：http://blog.csdn.net/paincupid/article/details/50321129（百度：java 正则表达式 邮政编码 ）
     * 验证手机号码（支持国际格式，+86135xxxx...（中国内地），+00852137xxxx...（中国香港））
     *
     * @param mobile 移动、联通、电信运营商的号码段
     *               <p>移动的号段：134(0-8)、135、136、137、138、139、147（预计用于TD上网卡）
     *               、150、151、152、157（TD专用）、158、159、187（未启用）、188（TD专用）</p>
     *               <p>联通的号段：130、131、132、155、156（世界风专用）、185（未启用）、186（3g）</p>
     *               <p>电信的号段：133、153、180（未启用）、189</p>
     *               补充：电信170 177
     * @return 验证成功返回true，验证失败返回false
     */
    public static boolean isMobile(String mobile) {
        String regex = "(\\+\\d+)?1[34578]\\d{9}$";
        return Pattern.matches(regex, mobile);
    }

    /**
     * 验证中国内地的座机号码
     * 来源：http://blog.csdn.net/paincupid/article/details/50321129（百度：java 正则表达式 邮政编码 ）
     * 区号+座机号码+分机号码
     * 注意：在中国，座机号码不能以1头，1分配给手机和特服；
     * 注意：座机号码的国际写法，86后面不能跟0
     *
     * @param fixedPhone
     * @return
     */
    public static boolean isFixedPhone(String fixedPhone) {
        // String reg="(?:(\\(\\+?86\\))(0[0-9]{2,3}\\-?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" +
        //        "(?:(86-?)?(0[0-9]{2,3}\\-?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)";

        // 二次开发
        // java api：(?:X) X，作为非捕获组
        // 百度：java正则表达式语法 http://baike.xsoftlab.net/view/207.html
        // (?:pattern)匹配pattern但不获取匹配结果，也就是说这是一个非获取匹配，不进行存储供以后使用。
        // 这在使用或字符“(|)”来组合一个模式的各个部分是很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。
        // 知识（规则）：
        // 1.固定电话号码（除开区号）不能1开头，1作为特殊服务（百度：固定电话1开头）；
        // 2.0作为长途电话识别码，不能作为固话号码（除开区号）首位（百度：固定电话0开头）；
        // 3.国内打座机长途，区号第一位为0，第二位非0数字（除开香港区号852，澳门区号853，内地打电话到香港和澳门是国际长途，区号前面还要加00）；
        // 4.座机号码的国际写法：86后面不能加国内长途识别码0，直接加区号；
        String regex = "(?:(\\(\\+86\\))([0-9]{2,3}\\-?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" + //座机的国际写法
                "(?:(\\(\\+86\\))([0-9]{2,3}[ ]?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" + //座机的国际写法
                "(?:(\\(\\+86\\))(\\([0-9]{2,3}\\))?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" + //座机的国际写法
                "(?:(\\+86\\-?)([0-9]{2,3}\\-?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" +//座机的国际写法
                "(?:(\\+86[ ]?)([0-9]{2,3}[ ]?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" +//座机的国际写法
                "(?:(0[0-9]{2,3}\\-?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" +
                "(?:(0[0-9]{2,3}[ ]?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" +
                "(?:(\\(0[0-9]{2,3}\\))?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|";
        return Pattern.matches(regex, fixedPhone);
    }

    /**
     * 验证国内单位的传真号码
     *
     * @param fax
     * @return
     */
    public static boolean isFax(String fax) {
        String regex = "(?:(\\(\\+86\\))([0-9]{2,3}\\-?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" + //传真的国际写法
                "(?:(\\(\\+86\\))([0-9]{2,3}[ ]?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" + //传真的国际写法
                "(?:(\\(\\+86\\))(\\([0-9]{2,3}\\))?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" + //传真的国际写法
                "(?:(\\+86\\-?)([0-9]{2,3}\\-?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" +//传真的国际写法
                "(?:(\\+86[ ]?)([0-9]{2,3}[ ]?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" +//传真的国际写法
                "(?:(0[0-9]{2,3}\\-?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" +
                "(?:(0[0-9]{2,3}[ ]?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" +
                "(?:(\\(0[0-9]{2,3}\\))?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|";

        return Pattern.matches(regex, fax);
    }

    /**
     * 判断字符串是实数
     *
     * @param str
     * @return
     */
    public static boolean isRealNumber(String str) {
        try {
            float f = Float.parseFloat(str);
        } catch (NumberFormatException e) {
            //logger.debug(e.getMessage(),e);
            return false;
        }

        return true;
    }

    /**
     * 判断字符串是实数
     *
     * @param str
     * @return
     */
    public static boolean isRealNumberByRegex(String str) {
        String regex = "";

        return Pattern.matches(regex, str);
    }

    /**
     * 比较Lis中元素的字典顺序，得到字典顺序最靠后的元素
     *
     * @param list
     * @return String 不会返回null
     */
    public static String getMaxOfList(List<String> list) {
        String max = "";

        for (String str : list) {
            if (str != null) {
                //必须判断非null，否则报java.lang.NullPointerException
                if (str.compareTo(max) > 0) {
                    max = str;
                }
            }
        }

        return max;
    }

    /**
     * 16进制字符串转字节数组 HexString——>byte
     *
     * @param hexString
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(
                    hexChars[pos + 1]));
        }
        return d;
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    /**
     * 字节数组转换为16进制字符串 <功能详细描述>
     *
     * @param src
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 生成随机码 <功能详细描述>
     *
     * @param number 生成随机码的位数
     * @return String [返回类型说明]
     * @throws throws [违例类型] [违例说明]
     */
    public static String randomCode(int number) {
        // 生成随机码
        String verifyCode = "";

        for (int i = 0; i < number; i++) {
            Random r = new Random();
            verifyCode += String.valueOf(r.nextInt(10));
        }
        return verifyCode;
    }

    /**
     * 判断是否为浮点数，包括double和float
     *
     * @param str
     * @return boolean true:是浮点数 false：不是浮点数
     * @throws throws [违例类型] [违例说明]
     * @see [类、类#方法、类#成员]
     */
    public static boolean isDouble(String str) {
        Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");
        return pattern.matcher(str).matches();
    }

    /**
     * 判断是否只包含数字
     *
     * @param str
     * @return boolean true:只包含数字，false：不全是数字
     * @see [类、类#方法、类#成员]
     */
    public static boolean isNumber(String str) {
        Pattern pattern = Pattern.compile("^[\\d]*$");
        return pattern.matcher(str).matches();
    }

    /**
     * 判断是否数字字母组合
     *
     * @param str 需要验证的参数
     * @return boolean true :是 false：不是
     * @see [类、类#方法、类#成员]
     */
    public static boolean isNumberOrLetter(String str) {
        if (null == str || "".equals(str)) {
            return false;
        } else {
            return Pattern.matches("^[0-9A-Za-z]+$", str);
        }
    }

    /**
     * 判断是否电子邮件格式
     *
     * @param str 需要验证的参数
     * @return boolean true：是 false：不是
     * @see [类、类#方法、类#成员]
     */
    public static boolean isEmail(String str) {
        if (null == str || "".equals(str)) {
            return false;
        } else {
            return Pattern
                    .matches("^(\\w)+(\\.\\w+)*@(\\w)+((\\.\\w+)+)$", str);
        }
    }

    /**
     * 把带单位的文件大小转换为不带单位的大小，不带单位的文件大小单位为byte；
     * <p>
     * 文件大小单位可以是，B、K、M、G
     *
     * @param fileSize 带单位文件大小
     * @return 返回-1表示转换出错
     * @see [类、类#方法、类#成员]
     */
    public static long fileSizeUnitToByte(String fileSize) {

        if (StringUtils.isBlank(fileSize)) {
            return -1;
        }

        // 获取文件大小单位
        String unit = fileSize.substring(fileSize.length() - 1);
        unit = unit.toUpperCase();
        if ((!"B".equals(unit)) && (!"K".equals(unit)) && (!"M".equals(unit))
                && (!"G".equals(unit))) {
            return -1;
        }

        // 获取文件大小数值部分
        String fileSizeNum = fileSize.substring(0, fileSize.length() - 1);
        if (!isDouble(fileSizeNum)) {
            return -1;
        }

        // 转化
        Double fileSizeD = Double.valueOf(fileSizeNum);
        if ("B".equals(unit)) {
            return fileSizeD.longValue();
        } else if ("K".equals(unit)) {
            Double fileSizeDK = fileSizeD * 1024;
            return fileSizeDK.longValue();
        } else if ("M".equals(unit)) {
            Double fileSizeDM = fileSizeD * 1024 * 1024;
            return fileSizeDM.longValue();
        } else if ("G".equals(unit)) {
            Double fileSizeDG = fileSizeD * 1024 * 1024 * 1024;
            return fileSizeDG.longValue();
        }

        return 0;
    }

    /**
     * 替换短信模板
     *
     * @param content
     * @param str
     * @return
     */
    public static String replaceContent(String content, String... str) {
        if (StringUtils.isEmpty(content)) {
            return "";
        }
        for (int i = 0; i < str.length; i++) {
            content = content.replaceAll("\\{" + i + "\\}", str[i]);
        }
        return content;
    }

    /**
     * 获取登录用户IP地址
     *
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (ip.equals("0:0:0:0:0:0:0:1")) {
            ip = "本地";
        }
        return ip;
    }

    /*测试*/
    public static void main(String[] args) {
        System.out.println(isPostCode("001234"));
        System.out.println(isPostCode("00"));
        System.out.println(isMobile("17057062756"));
        System.out.println(isFixedPhone("400-668-0000"));
        //手机的国内写法
        System.out.println("-----------手机的国内写法-------------");
        System.out.println(isMobile("18613219125"));
        //手机国际写法
        System.out.println("------------手机的国际写法------------");
        System.out.println(isMobile("+8618613219125"));
        //座机的国内写法
        System.out.println("-----------座机的国内写法-------------");
        System.out.println(isFixedPhone("057382651630"));
        System.out.println(isFixedPhone("0573-82651630"));
        System.out.println(isFixedPhone("0573 82651630"));
        System.out.println(isFixedPhone("(0573)82651630"));
        System.out.println(isFixedPhone("(573)82651630"));
        //座机的国际写法
        System.out.println("------------座机的国际写法------------");
        System.out.println(isFixedPhone("(+86)57382651630"));
        System.out.println(isFixedPhone("(+86)(573)82651630"));
        System.out.println(isFixedPhone("+8657382651630"));
        System.out.println(isFixedPhone("+86-573-82651630"));
        System.out.println(isFixedPhone("+86 573 82651630"));
        //传真的国内写法
        System.out.println("-----------传真的国内写法-------------");
        System.out.println(isFax("82651431"));
        System.out.println(isFax("0573-82651431"));
        System.out.println(isFax("0573 82651431"));
        System.out.println(isFax("(0573)82651431"));
        System.out.println(isFax("(573)82651431"));
        //传真的国际写法
        System.out.println("-----------传真的国际写法-------------");
        System.out.println(isFax("(+86)57382651431"));
        System.out.println(isFax("(+86)(573)82651431"));
        System.out.println(isFax("+8657382651431"));
        System.out.println(isFax("+86-573-82651431"));
        System.out.println(isFax("+86 573 82651431"));
        //验证字符串是数字
        System.out.println("-----------验证字符串是数字-------------");
        System.out.println(isRealNumber(" ")); //先打印异常，再打印返回值
        System.out.println(isRealNumber(""));
        System.out.println(isRealNumber("11"));
        System.out.println(isRealNumber("11.5"));
        System.out.println(isRealNumber("-11.5"));
        System.out.println(isRealNumber("-11"));
        System.out.println(isRealNumber("-011"));
        System.out.println(isRealNumber("E11.5"));
        System.out.println(isFixedPhone("0231111111"));
    }
}
